using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using WindowsUserControl.Dialogs;

namespace Workflows.Components.ETL
{
    public partial class SaveToDBEditor : Form,IComponentEditor 
    {
        private Type _SrcObjType;
        private List<TableColumn> _SrcTblSchema;
        private object ownerActivityNode;
        private SaveToDBComponent saveToDbComponent;

        public SaveToDBEditor()
        {
            InitializeComponent();
        }

        private void SaveToDBEditor_Load(object sender, EventArgs e)
        {
            this.cbo_SrcType.Items.Clear();
            for (int i = 0; i <= 1;i++)
            {
                TableDataFeedType feedType = (TableDataFeedType) i;
                this.cbo_SrcType.Items.Add(feedType.ToString());
            }
            this.cbo_UpdateAction.Items.Clear();
            for(int i=0;i<=2;i++)
            {
                TableUpdateAction action = (TableUpdateAction) i;
                this.cbo_UpdateAction.Items.Add(action.ToString());
            }
        }

        public event UpdateComponentSettings UpdateComponentSettingEvent;

        public object OwnerActivityNode
        {
            get { return ownerActivityNode; }
            set { ownerActivityNode = value; }
        }

        public Type WorkflowComponentType
        {
            get { return typeof(SaveToDBComponent); }
        }

        public void LoadSettings(
            GlobalVariable[] globalVars,
            WorkflowComponentBase[] fromComponents, 
            object activityNode, WorkflowComponentBase wfComponent)
        {
            try
            {
                this.ownerActivityNode = activityNode;
                this.saveToDbComponent = (SaveToDBComponent) wfComponent;
                this.cbo_SrcType.SelectedIndex = (int) this.saveToDbComponent.TableFeedType;
                this.cbo_UpdateAction.SelectedIndex = (int) this.saveToDbComponent.UpdateAction;
                this.txt_ConnStr.Text = this.saveToDbComponent.ConnectionString;
                this.btn_RefreshTables_Click(this, new EventArgs());
                this.cbo_TblNames.SelectedText = this.saveToDbComponent.TableName;
                this.cbo_Fields.SelectedText = this.saveToDbComponent.PkField;
                this.ck_IdentityInsert.Checked = this.saveToDbComponent.EnableIdentityInsert;
                if (this.saveToDbComponent.FieldMappings != null && this.saveToDbComponent.FieldMappings.Count > 0)
                {
                    this.ck_FieldMappings.Checked = true;
                }
                else
                {
                    this.ck_FieldMappings.Checked = false;
                }
                if (this.saveToDbComponent.TableFeedType == TableDataFeedType.ObjectListInMemory)
                {
                    this._SrcObjType = this.GetType(this.saveToDbComponent.SrcObjectTypeName);
                    this.InitFieldMappings(this._SrcObjType, this.saveToDbComponent.ConnectionString,
                                           this.saveToDbComponent.TableName, this.saveToDbComponent.FieldMappings);
                }
                else
                {
                    this._SrcTblSchema = this.saveToDbComponent.SourceTableColumns;
                    this.InitFieldMappings(this.saveToDbComponent.SourceTableColumns,
                                           this.saveToDbComponent.ConnectionString, this.saveToDbComponent.TableName,
                                           this.saveToDbComponent.FieldMappings);
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private Type GetType(string typeFullName)
        {
            string binFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            DirectoryInfo dirInfo = new DirectoryInfo(binFolderPath);
            FileInfo[] dllInfos = dirInfo.GetFiles("*.dll", SearchOption.TopDirectoryOnly);
            foreach (FileInfo dllInfo in dllInfos)
            {
                Assembly assem = Assembly.LoadFile(dllInfo.FullName);
                Type[] types = assem.GetTypes();
                foreach (Type type in types)
                {
                    if (type.FullName == typeFullName)
                        return type;
                }
            }
            return null;
        }

        public TestResult Test()
        {
            return new TestResult(true, string.Empty);
        }

        public void SaveSettings()
        {
            this.saveToDbComponent.TableFeedType = (TableDataFeedType) this.cbo_SrcType.SelectedIndex;
            this.saveToDbComponent.UpdateAction = (TableUpdateAction) this.cbo_UpdateAction.SelectedIndex;
            if(this.saveToDbComponent.TableFeedType==TableDataFeedType.ObjectListInMemory)
            {
                this.saveToDbComponent.SrcObjectTypeName = this._SrcObjType.FullName;
            }
            else
            {
                this.saveToDbComponent.SourceTableColumns = this._SrcTblSchema;
            }
            this.saveToDbComponent.ConnectionString = this.txt_ConnStr.Text;
            // this.btn_RefreshTables_Click(this,new EventArgs());
            this.saveToDbComponent.TableName = this.cbo_TblNames.Text;

            this.saveToDbComponent.PkField = this.cbo_Fields.Text;
            this.saveToDbComponent.EnableIdentityInsert = this.ck_IdentityInsert.Checked;
            this.saveToDbComponent.FieldMappings = null;
            if(this.ck_FieldMappings.Checked)
            {
                this.saveToDbComponent.FieldMappings=new Dictionary<string, string>();
                foreach(DataGridViewRow dr in this.dv_FieldMappings.Rows)
                {
                    if(!dr.IsNewRow)
                    {
                        string srcFieldName = dr.Cells[0].Value.ToString();
                        string tgtFieldName = dr.Cells[1].Value.ToString();
                        this.saveToDbComponent.FieldMappings.Add(srcFieldName,tgtFieldName);
                    }
                }
            }
        }

        private void btn_RefreshTables_Click(object sender, EventArgs e)
        {
            string[] tblNames = DbUtil.GetTables(this.txt_ConnStr.Text);
            this.cbo_TblNames.Items.Clear();
            this.cbo_TblNames.SelectedIndex = -1;
            this.cbo_TblNames.Text = string.Empty;
            if(tblNames !=null && tblNames.Length>0)
            {
                foreach(string tblName in tblNames)
                {
                    this.cbo_TblNames.Items.Add(tblName);
                }
            }
        }

        private void cbo_TblNames_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_TblNames.SelectedIndex>=0)
            {
                string tblName = this.cbo_TblNames.SelectedItem.ToString();
                string connStr = this.txt_ConnStr.Text;
                string[] fieldNames = 
                    DbUtil.GetTableColumnNames(
                        DataProviderType.MSSQL, 
                        connStr, 
                        string.Empty, 
                        tblName);
                this.cbo_Fields.Items.Clear();
                this.cbo_Fields.SelectedIndex = -1;
                this.cbo_Fields.Text = string.Empty;
                if(fieldNames !=null && fieldNames.Length>0)
                {
                    foreach(string fieldName in fieldNames)
                    {
                        this.cbo_Fields.Items.Add(fieldName);
                    }
                }
            }
        }

        private void ck_FieldMappings_CheckedChanged(object sender, EventArgs e)
        {
            if(this.ck_FieldMappings.Checked)
            {
                this.dv_FieldMappings.Enabled = true;
            }
            else
            {
                this.dv_FieldMappings.Enabled = false;
            }
        }

        private void btn_SelectTypeOrTable_Click(object sender, EventArgs e)
        {
            if (this.cbo_SrcType.SelectedIndex >= 0)
            {
                TableDataFeedType feedType = (TableDataFeedType) this.cbo_SrcType.SelectedIndex;
                if(feedType==TableDataFeedType.ObjectListInMemory)
                {
                    ReflectionBrowser objBrowser=new ReflectionBrowser();
                    objBrowser.OnTypeSelected += new SelectedType(objBrowser_OnTypeSelected);
                    objBrowser.Show(this);
                }
                else
                {
                    TableSchemaDialog tblSchemaDlg=new TableSchemaDialog();
                    tblSchemaDlg.OnTableSchemaDefined += new TableSchemaDefined(tblSchemaDlg_OnTableSchemaDefined);
                    tblSchemaDlg.Show(this);
                }
            }
        }

        void tblSchemaDlg_OnTableSchemaDefined(List<TableColumn> cols)
        {
            this._SrcTblSchema = cols;
            this.lbl_SrcTypeDesc.Text = "source data table defined";
        }

        void objBrowser_OnTypeSelected(Type type)
        {
            this._SrcObjType = type;
            this.lbl_SrcTypeDesc.Text = this._SrcObjType.Name;
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {
            this.SaveSettings();
            if(this.UpdateComponentSettingEvent !=null)
            {
                this.UpdateComponentSettingEvent(this.ownerActivityNode, this.saveToDbComponent);
            }
            this.Close();
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void InitFieldMappings(Type srcType, string tgtConnStr, string tgtTblName, Dictionary<string,string> fieldMappings)
        {
            this.dv_FieldMappings.Rows.Clear();
            FieldInfo[] fields = srcType.GetFields();
            string[] tblColNames =
                DbUtil.GetTableColumnNames(DataProviderType.MSSQL, tgtConnStr, string.Empty, tgtTblName);
            foreach(FieldInfo field in fields)
            {
                if(!field.IsStatic)
                {
                    DataGridViewRow dr=new DataGridViewRow();
                    DataGridViewTextBoxCell cellSrc=new DataGridViewTextBoxCell();
                    cellSrc.Value = field.Name;
                    dr.Cells.Add(cellSrc);
                    DataGridViewComboBoxCell cellTgt=new DataGridViewComboBoxCell();
                    foreach(string colName in tblColNames)
                    {
                        cellTgt.Items.Add(colName);
                    }
                    if(fieldMappings.ContainsKey(field.Name))
                    {
                        cellTgt.Value = fieldMappings[field.Name];
                    }
                    dr.Cells.Add(cellTgt);
                    this.dv_FieldMappings.Rows.Add(dr);
                }
            }
            PropertyInfo[] props = srcType.GetProperties();
            foreach(PropertyInfo prop in props)
            {
                DataGridViewRow dr = new DataGridViewRow();
                DataGridViewTextBoxCell cellSrc = new DataGridViewTextBoxCell();
                cellSrc.Value = prop.Name;
                dr.Cells.Add(cellSrc);
                DataGridViewComboBoxCell cellTgt = new DataGridViewComboBoxCell();
                foreach (string colName in tblColNames)
                {
                    cellTgt.Items.Add(colName);
                }
                if(fieldMappings.ContainsKey(prop.Name))
                {
                    cellTgt.Value = fieldMappings[prop.Name];
                }
                dr.Cells.Add(cellTgt);
                this.dv_FieldMappings.Rows.Add(dr);
            }
        }

        private void InitFieldMappings(List<TableColumn> srcTableCols, string tgtConnStr, string tgtTblName, Dictionary<string ,string> fieldMappings)
        {
            this.dv_FieldMappings.Rows.Clear();
            string[] tblColNames =
                DbUtil.GetTableColumnNames(DataProviderType.MSSQL, tgtConnStr, string.Empty, tgtTblName);
            foreach (TableColumn col in srcTableCols)
            {
                DataGridViewRow dr=new DataGridViewRow();
                DataGridViewTextBoxCell cellSrc=new DataGridViewTextBoxCell();
                cellSrc.Value = col.ColumnName;
                dr.Cells.Add(cellSrc);
                DataGridViewComboBoxCell cellTgt = new DataGridViewComboBoxCell();
                foreach (string colName in tblColNames)
                {
                    cellTgt.Items.Add(colName);
                }
                if(fieldMappings.ContainsKey(col.ColumnName))
                {
                    cellTgt.Value = fieldMappings[col.ColumnName];
                }
                dr.Cells.Add(cellTgt);
                this.dv_FieldMappings.Rows.Add(dr);
            }
        }

        private void btn_RefreshFieldMappings_Click(object sender, EventArgs e)
        {
            TableDataFeedType feedType = (TableDataFeedType) this.cbo_SrcType.SelectedIndex;
            if (feedType == TableDataFeedType.ObjectListInMemory)
            {
                this.InitFieldMappings(this._SrcObjType, this.txt_ConnStr.Text,
                                       this.cbo_TblNames.SelectedItem.ToString(), this.saveToDbComponent.FieldMappings);
            }
            else
            {
                this.InitFieldMappings(this._SrcTblSchema, this.txt_ConnStr.Text,
                                       this.cbo_TblNames.SelectedItem.ToString(), this.saveToDbComponent.FieldMappings);
            }
        }
    }
}